use std::collections::HashMap;

use model_graph_common::transport::http::http_get;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use tauri::http::{version::Version, HeaderName, HeaderValue, Method};

use crate::data_channels::{message::Message, request::request_response};

use model_graph_types::channel::{HttpMethod, HttpRequest, HttpResponse};

pub async fn http_request(
    peer_id: &String,
    request: HttpRequest,
    timeout: u64,
) -> anyhow::Result<HttpResponse> {
    tracing::debug!("请求节点:{}", peer_id);
    //
    let request_bytes = bincode::serialize(&request)
        .map_err(|err| anyhow::anyhow!("{}", err))?
        .to_vec();

    let message = Message::request(request_bytes);
    //发送
    tracing::debug!("开始发送请求:{}", message.data.len());
    let response_message = request_response(&peer_id, message, timeout).await?;
    tracing::debug!("获取请求数据:{}", response_message.data.len());
    //
    let response = bincode::deserialize::<HttpResponse>(&response_message.data[..])
        .map_err(|err| anyhow::anyhow!("{}", err))?;

    Ok(response)
}

pub async fn tauri_http_request(
    tauri_request: tauri::http::Request<Vec<u8>>,
) -> anyhow::Result<tauri::http::Response<Vec<u8>>> {
    let (peer_id, request) = _request_from_tauri_request(tauri_request)?;
    //
    let response = http_request(&peer_id, request, 60000).await?;

    let mut builder = tauri::http::Response::builder();
    let headers = builder
        .headers_mut()
        .map_or(Err(anyhow::anyhow!("")), |v| Ok(v))?;
    //  header
    for (key, value) in &response.headers {
        //
        headers.insert(
            HeaderName::from_str(key.as_str()).unwrap(),
            HeaderValue::from_str(value.as_str()).unwrap(),
        );
    }

    Ok(builder.status(response.status).body(response.body)?)
}

fn _request_from_tauri_request(
    request: tauri::http::Request<Vec<u8>>,
) -> anyhow::Result<(String, HttpRequest)> {
    let mut url = request.uri().clone();
    let method = request.method();
    let version = request.version();
    let body = request.body();
    let request_headers = request.headers();

    //
    tracing::debug!("{:#?}", url);

    let host = url.host().map_or("localhost", |v| v);
    let port = url.port_u16().map_or(80, |v| v);
    let path = url.path();
    let query = url.query().map_or(String::new(), |v| format!("?{}", v));

    //host:  peer_id.host
    let (peer_id, host) = host.split_at(
        host.find(".")
            .map_or(Err(anyhow::anyhow!("peer_id.host")), |v| Ok(v))?,
    );

    let (_, host) = host.split_at(1);
    //
    tracing::debug!("{},[{}],{}", peer_id, host, port);

    //
    let src_origin = format!("http://");
    let new_origin = format!("");

    let mut headers: HashMap<String, String> = HashMap::new();

    for (header_key, header_value) in request_headers {
        //referer
        if header_key.as_str().to_lowercase() == "referer" {
            // entry.set_key(capnp::text::Reader(b"referer"));
            // entry.set_value(capnp::text::Reader(value.as_bytes()));
        }
        if header_key.as_str().to_lowercase() == "host" {
            headers.insert(String::from("referer"), format!("{}:{}", host, port));
        } else {
            if let Ok(value) = header_value.to_str() {
                headers.insert(header_key.to_string(), value.to_string());
            }
        }
    }

    let mut extensions: HashMap<String, String> = HashMap::new();

    //
    Ok((
        String::from(peer_id),
        HttpRequest {
            url: format!("http://{}:{}{}{}", host, port, path, query),
            method: HttpMethod::try_from(method.as_str().to_string())?,
            version: format!("{:?}", version).to_uppercase(),
            headers: headers,
            body: Some(body.clone()),
            extensions: extensions,
        },
    ))
}

pub async fn local_execute_http_request(request_message: Message) -> anyhow::Result<Message> {
    //
    let request: HttpRequest = bincode::deserialize::<HttpRequest>(&request_message.data[..])
        .map_err(|err| anyhow::anyhow!("{}", err))?;

    let response = _execute_http_request(request).await?;

    let response_bytes = bincode::serialize(&response)
        .map_err(|err| anyhow::anyhow!("{}", err))?
        .to_vec();

    let message = Message::response(response_bytes);

    Ok(message)
}

async fn _execute_http_request(request: HttpRequest) -> anyhow::Result<HttpResponse> {
    let url = &request.url;
    let headers = &request.headers;

    //headers
    let mut header_map = reqwest::header::HeaderMap::new();
    for (key, value) in headers {
        header_map.insert(
            HeaderName::from_bytes(key.as_bytes())?,
            value.as_str().parse()?,
        );
    }
    let body = &request.body;

    //method
    let request = match &request.method {
        HttpMethod::Get => reqwest::Client::new().get(url).headers(header_map),
        HttpMethod::Post => reqwest::Client::new().post(url).headers(header_map),
        HttpMethod::Put => reqwest::Client::new().put(url).headers(header_map),
        HttpMethod::Delete => reqwest::Client::new().delete(url).headers(header_map),
        _ => reqwest::Client::new().get(url).headers(header_map),
    };
    let body_vec = if let Some(body_vec) = body {
        body_vec.to_vec()
    } else {
        vec![]
    };

    tracing::debug!("开始请求:{}", url);
    let response = request
        .body(body_vec)
        .send()
        .await
        .map_err(|err| anyhow::anyhow!("请求错误:{}", err))?;

    //status code
    let status = response.status().as_u16();
    //
    let mut response_headers: HashMap<String, String> = HashMap::new();
    for (header_key, header_value) in response.headers() {
        if let Ok(value) = header_value.to_str() {
            response_headers.insert(header_key.to_string(), value.to_string());
        }
    }

    let content = response
        .bytes()
        .await
        .map_err(|err| anyhow::anyhow!("获取内容失败:{}", err))?;

    Ok(HttpResponse {
        status: status,
        headers: response_headers,
        body: content.to_vec(),
    })
}
